package model;

import java.util.ArrayList;
import java.util.List;

import model.configuration.ConfigData;
import model.database.ObjectDataProvider;
import model.exception.NoStoreProcedureNameGiven;

public abstract class BaseDAO {

	protected String insertStoreProcedureName; // store procedure for save object 
	protected String updateStoreProcedureName; // store procedure for change object data in database
	protected String deleteStoreProcedureName; // store procedure for delete object data from database
	protected String selectStoreProcedureName; // store procedure for select data
	
	public BaseDAO() {
		setStoredProcedureName(); // set stored procedure name to manipulate object data in database
	}
	
	protected abstract void setStoredProcedureName();
	
	private void insertData2DB(BaseObject objectForInsert) throws Exception {
		if (insertStoreProcedureName == null) {
			throw new NoStoreProcedureNameGiven();
		}
		else {
			objectForInsert.id = ((BaseObject) ObjectDataProvider.sendObject2GetObject(objectForInsert, objectForInsert.getClass(), insertStoreProcedureName)).getId();
		}
		
	}
	
	private void updateDataInDB(BaseObject objectForUpdate) throws Exception {
		if (updateStoreProcedureName == null) {
			throw new NoStoreProcedureNameGiven();
		} else {
			ObjectDataProvider.sendObject2GetObject(objectForUpdate, objectForUpdate.getClass(), updateStoreProcedureName);
		}
	}
	
	private void deleteDataInDB(BaseObject objectForDelete) throws Exception {
		if (deleteStoreProcedureName == null) {
			throw new NoStoreProcedureNameGiven();
		} else {
			ObjectDataProvider.sendObject2GetObject(objectForDelete, objectForDelete.getClass(), deleteStoreProcedureName);
		}
	}

	/**
	 * Save object in database
	 * @throws Exception
	 */
	public void save(BaseObject objectForSave) throws Exception {
		if (objectForSave.id == ConfigData.NOVALUELONG) {
			insertData2DB(objectForSave); // add data to database
		}
		else {
			updateDataInDB(objectForSave); // change exist data in database
		}
	}
	
	protected List selectObjectList(Object parameter) throws Exception {
		List<Object> result = new ArrayList<Object>(); 
		if (selectStoreProcedureName == null) {
			throw new NoStoreProcedureNameGiven();
		}
		else {
			// in current implementation parameterList can not be null, if so, use current class as parameter list 
			result = ObjectDataProvider.sendObject2GetListObject((parameter!=null) ? parameter:this, (parameter!=null) ? parameter.getClass():this.getClass(), selectStoreProcedureName);
		}
		return result;
		
	}
	
	public void delete(BaseObject objectForDelete) throws Exception {
		deleteDataInDB(objectForDelete);
	}
	
//    // This must return true for another class object with same id.
//    public boolean equals(Object other) {
//        return other instanceof BaseObject && (id != null) ? id.equals(((BaseObject) other).id) : (other == this);
//    }
//
//    // This must return the same hashcode for every class object with the same id.
//    public int hashCode() {
//        return id != null ? this.getClass().hashCode() + id.hashCode() : super.hashCode();
//    }
//    
//    @Override
//    protected Object clone() throws CloneNotSupportedException {
//    	//TODO delete or change
//    	BaseObject newBaseObject = (BaseObject) super.clone();
//    	newBaseObject.id = this.id;
//    	return newBaseObject;
//    }
	
}
